package com.tangyuan.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tangyuan.common.result.Result;
import com.tangyuan.common.result.ResultCodeEnum;
import com.tangyuan.common.util.RedisUtil;
import com.tangyuan.common.util.StringUtils;
import com.tangyuan.dto.UserActionByUserIdDto;
import com.tangyuan.dto.UserActionDto;
import com.tangyuan.enums.ActionConstant;
import com.tangyuan.feignapis.video.IVideoHotFeignClient;
import com.tangyuan.model.UserAction;
import com.tangyuan.user.mapper.UserActionMapper;
import com.tangyuan.user.service.UserActionService;
import com.tangyuan.user.service.UserLikeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 小梁
 * @since 2020-12-03
 */
@Service
@Slf4j
public class UserActionServiceImpl extends ServiceImpl<UserActionMapper, UserAction> implements UserActionService {

    @Autowired
    private UserLikeService userLikeService;

    @Autowired
    private IVideoHotFeignClient videoHotFeignClient;
    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private UserActionMapper userActionMapper;


    @Override
    public int updateUserAction(UserActionDto dto) {
        float tempGrade = 0;
        float tempCollection = 0;
        float score = 0;
        float tempThump = 0;

        tempGrade = ActionConstant.GRADE_WEIGHT_F * dto.getGrade();
        tempCollection = ActionConstant.COLLECTION_WEIGHT_F * dto.getCollection();
        tempThump = ActionConstant.THUMP_WEIGHT_F * dto.getThump();
        score = tempGrade + tempCollection + tempThump;

        LambdaQueryWrapper<UserAction> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(UserAction::getUserId, dto.getUserId()).eq(UserAction::getMovieId, dto.getMovieId()).last("limit 1");
        UserAction userAction = baseMapper.selectOne(lambdaQueryWrapper);
        if (userAction == null) {
            userAction = new UserAction();
            userAction.setUserId(dto.getUserId());
            userAction.setMovieId(dto.getMovieId());
            userAction.setGrade(tempGrade + tempThump);
            userAction.setCollection(tempCollection);
            userAction.setView(1F);
            userAction.setViewNumber(1);
            userAction.setScore(score);
            userAction.setViewTime(new Date());
            return baseMapper.insert(userAction);
        } else {
            userAction.setGrade(userAction.getGrade() + tempGrade + tempThump);
            userAction.setCollection(userAction.getCollection() + tempCollection);
            userAction.setScore(userAction.getScore() + score);
            return baseMapper.updateById(userAction);
        }
    }

    /**
     * 添加用户行为
     *
     * @param userId
     * @param movieId
     * @return
     */
    @Override
    public synchronized int addUserAction(Long userId, Long movieId) {
        UserAction action = baseMapper.selectOne(new LambdaQueryWrapper<UserAction>()
                .eq(UserAction::getUserId, userId).eq(UserAction::getMovieId, movieId).last("limit 1"));
        if(action == null){
            action = new UserAction();
            action.setUserId(userId);
            action.setMovieId(movieId);
            action.setView(1F);
            action.setGrade(0F);
            action.setCollection(0F);
            action.setScore(1F);
            action.setViewTime(new Date());
            action.setViewNumber(1);
            return baseMapper.insert(action);
        }else {
            return baseMapper.update(null,new LambdaUpdateWrapper<UserAction>()
                    .eq(UserAction::getAId,action.getAId())
                    .set(UserAction::getViewTime,new Date())
                    .set(UserAction::getViewNumber,action.getViewNumber() + 1));
        }
    }


    @Override
    public List<UserAction> getUserActionCollection() {
        return baseMapper.selectList(null);
    }

    @Override
    public List<Long> getAllUserMovieId() {
        QueryWrapper<UserAction> wrapper = new QueryWrapper<>();
        wrapper.select("DISTINCT movie_id").orderByAsc("movie_id");
        List<UserAction> userActions = baseMapper.selectList(wrapper);
        List<Long> list = new ArrayList<Long>();
        for (UserAction userAction : userActions) {
            list.add(userAction.getMovieId());
        }
        return list;
    }

    @Override
    public List<Long> getAllUserId() {
        QueryWrapper<UserAction> wrapper = new QueryWrapper<>();
        wrapper.select("DISTINCT user_id").orderByAsc("user_id");
        List<UserAction> userActions = baseMapper.selectList(wrapper);
        List<Long> list = new ArrayList<Long>();
        for (UserAction userAction : userActions) {
            list.add(userAction.getUserId());
        }
        return list;
    }

    @Override
    public void view(UserAction userAction) {
        Long userId = userAction.getUserId();
        Long movieId = userAction.getMovieId();
        this.addUserAction(userId, movieId);
        String key = Long.toString(userId);
        videoHotFeignClient.browseHot(movieId);
        if (redisUtil.hasKey(key) && redisUtil.lGetListSize(key) > 7) {
            // 大于7先弹出
            redisUtil.rPop(key);
            // 再表头插入
            redisUtil.lSet(key, movieId);
        } else {
            redisUtil.lSet(key, movieId);
        }
        // 底层逻辑是增加过一次之后就不再增加，所以直接返回成功，解决原来第二次浏览就会407错误问题
    }

    @Override
    public Result<String> action(UserActionDto dto) {
        if (dto.getUserId() == null || dto.getMovieId() == null) {
            return Result.build(null, ResultCodeEnum.ARGUMENT_VALID_ERROR);
        }
        if (dto.getGrade() == 0f && dto.getCollection() == 0f && dto.getThump() == 0f) {
            return Result.build(null, ResultCodeEnum.NOT_VIEW_MOVIE);
        }
        if(Math.abs(dto.getGrade()) < 1.0f && Math.abs(dto.getCollection()) < 1.0f && Math.abs(dto.getThump()) < 1.0f){
            return Result.build(null, ResultCodeEnum.ARGUMENT_VALID_ERROR);
        }
        int i = this.updateUserAction(dto);
        int flag = userLikeService.updateUser(dto);
        if (flag > 0) {
            // 成功
            if (i > 0) {
                return Result.ok();
            } else {
                log.info("更改用户行为任务失败:用户ID:{},视频ID:{}",dto.getUserId(),dto.getMovieId());
                return Result.build(null, ResultCodeEnum.NOT_VIEW_MOVIE);
            }
        } else {
            log.info("更改用户喜欢蓝图行任务失败:用户ID:{},视频ID:{}",dto.getUserId(),dto.getMovieId());
            return Result.build(null, ResultCodeEnum.NOT_VIEW_MOVIE);
        }
    }

    @Override
    public List<Long> getUserActionByUserIdDto(UserActionByUserIdDto userActionByUserIdDto) {
        return userActionMapper.getUserActionByUserIdDto(
                userActionByUserIdDto.getUserId(),
                userActionByUserIdDto.getUserIds(),
                userActionByUserIdDto.getJustScore(),
                userActionByUserIdDto.getLoseScore());
    }

    @Override
    public List<Long> getUserActionByUserId(Long userId) {
        return userActionMapper.getUserActionByUserId(userId);
    }

    @Override
    public Page<UserAction> getPageUserActionByUserId(Long userId, Integer pageNum, Integer pageSize) {
        QueryWrapper<UserAction> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(UserAction::getUserId,userId);
        wrapper.lambda().orderByDesc(UserAction::getViewTime);
        return baseMapper.selectPage(new Page<>(pageNum,pageSize),wrapper);
    }

    @Override
    public void deleteUserAction() {
        userActionMapper.deleteAll();
    }

    @Override
    public List<UserAction> selectUserActionList(Long userId,String sort) {
        QueryWrapper<UserAction> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        if (StringUtils.isNotEmpty(sort)){
            wrapper.orderByAsc(sort);
        }
        return userActionMapper.selectList(wrapper);
    }

    @Override
    public List<UserAction> selectUserActionListByDistinct() {
        QueryWrapper<UserAction> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("DISTINCT user_id")
                .orderByAsc("user_id");
        return userActionMapper.selectList(queryWrapper);
    }

    @Override
    public List<UserAction> getYesterdayUserActionData(Date time) {
        return userActionMapper.getYesterdayUserActionData(time);
    }
}
